#include "database.h"
#include "mediaitemimpl.h"
#include <QDomDocument>

Database::Database()
{
}

void Database::save(const QString & filename)
{
    QDomDocument doc("library");
    QDomElement root = doc.createElement("library");
    doc.appendChild(root);
    foreach(MediaItemPtr item, m_items) {
        QDomElement el = doc.createElement("item");
        root.appendChild(el);
        item->impl()->save(el);
    }
    QString s = doc.toString();
    QFile file(filename);
    if(!file.open(QIODevice::WriteOnly))
        return;
    file.write(s.toUtf8());
    file.close();
}

void Database::load(const QString & filename)
{
    QDomDocument doc("library");
    QFile file(filename);
    if(!file.open(QIODevice::ReadOnly))
        return;
    if(!doc.setContent(&file)) {
        file.close();
        return;
    }
    file.close();
    QDomElement root = doc.documentElement();
    for(QDomElement el = root.firstChildElement("item"); !el.isNull(); el = el.nextSiblingElement("item")) {
        MediaItemPtr item(new MediaItemImpl);
        item->impl()->load(el);
        add(item);
    }
}

QList<MediaItemPtr> Database::all()
{
    return m_items.toList();
}

QStringList Database::keywords()
{
    return m_keywords.toList();
}

QStringList Database::collections()
{
    return m_collections.toList();
}

QSet<MediaItemPtr> Database::group(MediaItemPtr item)
{
    QString id = groupid(item->impl()->metadata());
    return m_group[id];
}

MediaItemPtr Database::item(const QString &filename)
{
    if(m_filename_index.contains(filename))
        return m_filename_index[filename];
    else
        return MediaItemPtr();
}

void Database::add(MediaItemPtr item)
{
    if(m_items.contains(item))
        return;
    m_items.insert(item);
    m_filename_index[item->metadata().filename] = item;
    QString id = groupid(item->impl()->metadata());
    //m_item_group[item] = id;
    m_group[id].insert(item);
    QSet<MediaItemPtr> notify = m_group[id];

    if(!item->metadata().collection.isEmpty() && !m_collections.contains(item->metadata().collection)) {
        m_collections.insert(item->metadata().collection);
        emit collectionsChanged();
    }

    QSet<QString> tmp = m_keywords;
    m_keywords.unite(item->metadata().keywords);
    if(m_keywords != tmp)
        emit keywordsChanged();

    emit added(item);
    foreach(MediaItemPtr tmp, notify)
        emit updated(tmp);
}

void Database::remove(MediaItemPtr item)
{
    m_items.remove(item);
    m_filename_index.remove(item->metadata().filename);
    QString id = groupid(item->impl()->metadata());// m_item_group.take(item);
    QSet<MediaItemPtr> & items = m_group[id];
    items.remove(item);
    QSet<MediaItemPtr> notify = items;
    if(items.empty())
        m_group.remove(id);
    emit removed(item);
    foreach(MediaItemPtr tmp, notify)
        emit updated(tmp);
}

void Database::update(MediaItemPtr item, const MediaItemImpl::Metadata & metadata)
{
    if(!m_items.contains(item))
        return;
    MediaItemImpl::Metadata old_metadata = item->impl()->metadata();
    item->impl()->m_metadata = metadata;

    if(metadata.filename != old_metadata.filename) {
        m_filename_index.remove(old_metadata.filename);
        m_filename_index[metadata.filename] = item;
    }

    QString old_id = groupid(old_metadata);
    QString new_id = groupid(metadata);
    QSet<MediaItemPtr> notify;
    if(new_id != old_id) {
        m_group[old_id].remove(item);
        notify = m_group[old_id] | m_group[new_id];
        if(m_group[old_id].empty())
            m_group.remove(old_id);
        m_group[new_id].insert(item);
    }

    // update collections list
    if(!item->metadata().collection.isEmpty() && !m_collections.contains(item->metadata().collection)) {
        m_collections.insert(item->metadata().collection);
        emit collectionsChanged();
    }

    // update keywords list
    QSet<QString> tmp = m_keywords;
    m_keywords.unite(item->metadata().keywords);
    if(m_keywords != tmp)
        emit keywordsChanged();

    emit updated(item);
    foreach(MediaItemPtr tmp, notify)
        emit updated(tmp);
}

QString Database::groupid(const MediaItemImpl::Metadata & metadata)
{
    return QFileInfo(metadata.filename).baseName() + "|" + metadata.created.toString();
}

QString Database::collection(const QString & root, const QString &filename)
{
    QString tmp = root;
    if(!tmp.endsWith('/'))
        tmp += '/';
    if(!filename.startsWith(tmp)) {
        return QString();
    }
    tmp = filename.mid(tmp.length());
    int p = tmp.indexOf(QChar('/'));
    if(p < 0)
        return QString();
    tmp = tmp.left(p);
    if(tmp.length() == 4 && tmp[0].isDigit() && tmp[1].isDigit() && tmp[2].isDigit() && tmp[3].isDigit())
        return QString();
    return tmp;
}
